
import { _decorator, Component, Node, instantiate, resources, Prefab, Asset, Vec3, Input, input, EventKeyboard, KeyCode, Camera, Quat, view, Size, MeshRenderer, Material, screen, RigidBody, math, Game, random } from 'cc';
import { GameMgr } from './GameMgr';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = MapMgr
 * DateTime = Sat Mar 05 2022 08:13:53 GMT+0800 (中国标准时间)
 * Author = lamd
 * FileBasename = MapMgr.ts
 * FileBasenameNoExtension = MapMgr
 * URL = db://assets/Scripts/MapMgr.ts
 * ManualUrl = https://docs.cocos.com/creator/3.4/manual/en/
 *
 */

const LongColumn: number = 6;
const ShortColumn: number = 10;
const Row: number = 12;

enum TileType {
    tile = "tile_white", // 瓷砖
    hold = "hold", // 空洞
    spike = "moving_spikes", // 地面尖刺
    skySpike = "smashing_spikes", // 天空落下尖刺
}

@ccclass('MapMaker')
export class MapMaker extends Component {
    // [1]
    // dummy = '';

    // [2]
    // @property
    // serializableDummy = 0;
    // @property({ type: Prefab })
    private pfbMap: Map<string, Prefab> = new Map(); // "tile_white"  "wall2"  "smashing_spikes"  "moving_spikes"  "gem2"
    private matMap: Map<string, Material> = new Map(); // "tile_white"  "wall2"  "smashing_spikes"  "moving_spikes"  "gem2"
    private resMap: Map<string, Asset> = new Map(); //  加载的资源
    private mapData: Node[][] = []; // 瓷砖数据

    private cameraNode: Node = null!;
    private mapNode: Node = null!;
    private winSize: Size = null!;
    private camerCom: Camera = null!; // 360*640  1.28

    private trailColors: math.Color[] = []; // 痕迹颜色

    private oddsHold: number = 0;   // 空洞概率
    private oddsSpike: number = 0;  // 尖刺概率
    private oddsSkySpike: number = 0;  //空中落下尖刺概率
    public dropRowIndex = 0;

    onLoad() {
        this.cameraNode = this.node.parent.getChildByName("Main Camera");
        this.mapNode = this.node.parent.getChildByName("Map");
        this.camerCom = this.cameraNode.getComponent(Camera);
    }

    start() {
        // 按键事件 用于测试
        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
        input.on(Input.EventType.KEY_PRESSING, this.onKeyDown, this);

        this.trailColors.push(new math.Color(110, 80, 165));
        this.trailColors.push(new math.Color(126, 93, 183));

        //     (.position); //.getComponent(Camera);
        console.log("0,0: worldToScreen :", this.camerCom.worldToScreen(new Vec3(0, 0, 0)));
        console.log("0,0: screenToWorld :", this.camerCom.screenToWorld(new Vec3(0, 0, 0)));

        input.on(Input.EventType.MOUSE_DOWN, (event) => {
            var pos = event.getLocationInView()
            console.log("click pos:", pos);
            console.log("click pos world:", this.camerCom.screenToWorld(new Vec3(pos.x, pos.y)));
        }, this);

        // tilePrefab = resources.preload("tile_white", Prefab)
        // resources.loadDir("Prefabs", (err, assets) => {
        //     for (let index = 0; index < assets.length; index++) {
        //         const element = assets[index];
        //         this.pfbMap.set(element.data.name, element);
        //     }

        //     this.createChunk();
        // });
        // console.log("resources.config:", resources.config);


        // resources.loadDir("Mats", (err, assets) => {
        //     for (let index = 0; index < assets.length; index++) {
        //         const element = assets[index];
        //         console.log(element);

        //         this.matMap.set(element.data.name, element);
        //     }

        //     this.createChunk();
        // });

        // this.createChunk()

        // resources.loadDir("resources", (err) => {
        //     if (!err) {
        //         console.log("载入成功");

        //         console.log(resources.get("Prefabs/gem2"));



        //         this.createChunk();
        //     }
        //     else
        //         console.log("载入失败");
        // })

        // this.winSize = view.getFrameSize();
        this.winSize = screen.windowSize;
        var pos = this.cameraNode.position
        // this.cameraNode.position = new Vec3(pos.x, pos.y+1.46*this.winSize.width*0.5) 
        // var pos = this.cameraNode.position
        // this.cameraNode.position = new Vec3(pos.x, pos.y + 1.46 * this.winSize.width / 320, pos.z)
        // console.log("camera position:" + this.cameraNode.position);

        // console.log("camera position:" + this.cameraNode.position);

        // if(this.winSize.height/this.winSize.width >  640/360)
        //     this.cameraNode.position = new Vec3(pos.x, 1.46 * this.winSize.width / 360, pos.z)

        // console.log("camera position:" + this.cameraNode.position);
        // if(this.winSize.height/this.winSize.width >  640/360)
        // this.cameraNode.getComponent(Camera).fov *= this.winSize.height/this.winSize.width;


    }

    public loadRes(finishCbk: Function) {
        var paths = resources.config.paths;
        var count = 0;
        paths.forEach((value, key) => {
            resources.load(key, (err, data) => {
                this.resMap.set(key, data);
                if (++count == paths.count) {
                    this.init();
                    finishCbk();
                }
            })
        })
    }

    init(){
        this.dropRowIndex = 0;
        
        for (let i = 0; i < this.mapData.length; i++) {
            for (let j = 0; j < this.mapData[i].length; j++) {
                this.mapData[i][j].destroy();
            }
        }
        this.mapData.splice(0, this.mapData.length);
        this.createChunk(0);
    }

    getRes(key: string, type: string): Asset {
        if (type == "Prefab") {
            return this.resMap.get("Prefabs/" + key)
        }
        else if (type == "Material")
            return this.resMap.get("Materails/" + key)
    }


    startDrop() {
        console.log("执行掉落 this.testDropRow:", this.dropRowIndex);
        this.schedule(this.dropRow.bind(this), 3)
    }

    // scaleTileWidth: number = 0.254;

    tileOffset: number = Math.pow(2, 0.5) * 0.245;   // 根号2的倍距离 

    // 创建一段地图 
    createChunk(offsetz: number) {
        // var winSize = screen.windowSize;
        // console.log("screen.windowSize.width:", winSize.width);
        // console.log("screen.windowSize.height:", winSize.height);
        // console.log("0,0 worldPos:", this.camerCom.screenToWorld(new Vec3(0, 0)));
        // console.log("-w/2, -h/2 worldPos:", this.camerCom.screenToWorld(new Vec3(-winSize.width/2,-winSize.height/2)));
        // console.log("w/2, h/2 worldPos:", this.camerCom.screenToWorld(new Vec3(winSize.width/2,winSize.height/2)));
        // console.log("w, h worldPos:", this.camerCom.screenToWorld(new Vec3(winSize.width,winSize.height)));

        // var minPos = this.camerCom.screenToWorld(new Vec3(-winSize.width/2,-winSize.height/2))
        // var offsetX = minPos.x*2
        // var offsetZ = minPos.y*2

        let pfbName: string = "";
        let matName: string = "";
        for (let i = 0; i < Row; i++) {
            let nodes: Node[] = [];
            this.mapData.push(nodes);
            for (let j = 0; j < LongColumn; j++) {
                const tileNode: Node = (j == 0 || j == LongColumn - 1) ? this.spawnWall() : this.spawnTile();
                tileNode.worldPosition = new Vec3(j * this.tileOffset - 0.87, 0, 0.7 - i * this.tileOffset + offsetz); // 1.33
                tileNode.eulerAngles = new Vec3(-90, 45, 0);
                this.mapNode.addChild(tileNode);

                if (j > 0 && j < LongColumn - 1 && tileNode.name == TileType.tile) {
                    let data: Material = this.getRes("colorTile1", "Material") as Material;
                    tileNode.getComponent(MeshRenderer).material = data;
                    tileNode.getChildByName("normal_a2").getComponent(MeshRenderer).material = data;
                }

                // if(j > 0 && j < LongColumn - 1)
                nodes.push(tileNode);
            }

            let nodes2: Node[] = [];
            this.mapData.push(nodes2);
            for (let j = 0; j < ShortColumn - 1; j++) {
                const tileNode: Node = this.spawnTile();
                tileNode.position = new Vec3((j + 0.5) * this.tileOffset - 0.87, 0, 0.7 - (i + 0.5) * this.tileOffset + offsetz);
                tileNode.eulerAngles = new Vec3(-90, 45, 0);
                this.mapNode.addChild(tileNode);

                if (tileNode.name == TileType.tile) {
                    let data: Material = this.getRes("colorTile2", "Material") as Material;
                    tileNode.getComponent(MeshRenderer).material = data;
                    tileNode.getChildByName("normal_a2").getComponent(MeshRenderer).material = data;
                }

                nodes2.push(tileNode);
            }
        }
    }

    calcOdds(): TileType {
        let rd: number = Math.floor(math.random() * 100);
        // if (rd <= this.oddsHold)
        //     return TileType.hold;
        // else if (rd <= this.oddsHold + this.oddsSpike)
        //     return TileType.spike;
        // else if (rd <= this.oddsHold + this.oddsSpike + this.oddsSkySpike)
        //     return TileType.skySpike;

        // return TileType.tile;
        return rd % 5 == 1 ? TileType.spike : TileType.tile;
    }

    spawnWall(): Node {
        let pfb: Prefab = this.getRes("wall2", "Prefab") as Prefab;
        let node: Node = instantiate(pfb) as Node;
        node.name = "wall";
        return node;
    }


    testindex = 1;
    spawnTile(): Node {
        let tileType: TileType = this.calcOdds()
        // let tileType: TileType = this.testindex++ == 1 ? TileType.spike : TileType.tile;// TileType.skySpike

        let node: Node = (tileType == TileType.hold) ? new Node() : instantiate(this.getRes(tileType, "Prefab") as Prefab) as Node;
        node.name = tileType;

        return node;
    }

    // 增加事故概率
    addBadOdds() {
        this.oddsHold = this.oddsHold < 25 ? this.oddsHold + 2 : this.oddsHold;
        this.oddsSpike = this.oddsSpike < 15 ? this.oddsSpike + 2 : this.oddsSpike;
        this.oddsSkySpike = this.oddsSkySpike < 15 ? this.oddsSkySpike + 2 : this.oddsSkySpike;
    }

    isHoldTile(column: number, row: number): boolean {
        return this.mapData[row][column].name == TileType.hold
    }

    // 普通瓷砖
    isTile(node: Node): boolean {
        return node.name == TileType.tile
    }

    update(deltaTime: number) {

        if (this.mapData.length > 0) {
            // console.log("drop y:", this.mapData[0][0].worldPosition.y);
        }


        // if (Input.EventType.KEY_DOWN) {
        // }

        // if (Input.EventType.KEY_DOWN) {
        // }

        // w=320 h=640  ==>  y=1.46
        // newY = 1.46*newW/320

        // var size = director.getWinSizeInPixels()
        // var size = view.getFrameSize();
        // console.log("getFrameSize:" + size);

        // if (this.winSize.width != size.width) {
        //     console.log("分辨率：" + view.getFrameSize());
        //     var pos = this.cameraNode.position
        //     this.cameraNode.position = new Vec3(pos.x, pos.y + 1.46 * this.winSize.width * 320, pos.z)
        //     console.log("camera position:" + this.cameraNode.position);
        // }
    }

    // 获取瓷砖数据
    // public getTileNode(column: number, row: number): Node {
    //     return this.mapData[row][column]
    // }

    public getTileNode(): Node[][] {
        return this.mapData
    }

    // 判断行数据
    public getRowNode(row: number): Node[] {
        return this.mapData[row]
    }

    // 是否长行
    public isLongRow(row: number): boolean {
        let rowCount: number = this.getRowNode(row).length
        return rowCount == LongColumn;
    }

    // 移动过的痕迹
    public trail(column: number, row: number) {
        let tile: Node = this.getTileNode()[row][column];
        if (tile.name != TileType.tile) return;

        let colorIndex: number = this.isLongRow(row) ? 0 : 1
        let color: math.Color = this.trailColors[colorIndex];

        tile.getComponent(MeshRenderer).material.setProperty("mainColor", color);
        tile.getComponentInChildren(MeshRenderer)?.material.setProperty("mainColor", color);
    }

    // b>a
    getRandom(a, b) {
        return a + math.random() * (b - a + 1);
    }
    // 下落一排
    dropRow() {
        console.log(" drip index:......", this.dropRowIndex);

        let nodes: Node[] = this.mapData[this.dropRowIndex];
        for (let index = 0; index < nodes.length; index++) {
            const tile = nodes[index];
            if (tile.name != TileType.hold) {
                let body: RigidBody = tile.getComponent(RigidBody)
                if (!body)
                    body = tile.addComponent(RigidBody);
                body.enabled = true;
                body.setAngularVelocity(new Vec3(this.getRandom(0, 10), this.getRandom(0, 10), this.getRandom(0, 10)));
            }
        }

        this.scheduleOnce(() => {
            for (let index = 0; index < nodes.length; index++) {
                nodes[index].destroy();
            }
            
            GameMgr.instance.recycleOneRow();
        }, 1)

        this.dropRowIndex++;
        GameMgr.instance.checkGameOverWithDrop();
    }

    onKeyDown(event: EventKeyboard) {
        if (event.keyCode == KeyCode.KEY_P) {
        }
        //  右移 
        if (event.keyCode == KeyCode.KEY_D) {
            const pos = this.mapNode.worldPosition;
            this.mapNode.worldPosition = new Vec3(pos.x + 0.01, pos.y, pos.z);
        }
        // 左移 
        if (event.keyCode == KeyCode.KEY_A) {
            const pos = this.mapNode.worldPosition;
            this.mapNode.worldPosition = new Vec3(pos.x - 0.01, pos.y, pos.z);
        }
        // 前移 
        if (event.keyCode == KeyCode.KEY_W) {
            const pos = this.mapNode.worldPosition;
            this.mapNode.worldPosition = new Vec3(pos.x, pos.y, pos.z - 0.01);
        }
        // 后移
        if (event.keyCode == KeyCode.KEY_S) {
            const pos = this.mapNode.worldPosition;
            this.mapNode.worldPosition = new Vec3(pos.x, pos.y, pos.z + 0.01);
        }

        // 摄像机高度
        if (event.keyCode == KeyCode.ARROW_UP) {
            const pos = this.cameraNode.worldPosition;
            this.cameraNode.worldPosition = new Vec3(pos.x, pos.y + 0.01, pos.z);
        }

        if (event.keyCode == KeyCode.ARROW_DOWN) {
            const pos = this.cameraNode.worldPosition;
            this.cameraNode.worldPosition = new Vec3(pos.x, pos.y - 0.01, pos.z);
        }


        // 正交模式摄像机 视口高度
        if (event.keyCode == KeyCode.DIGIT_1) {
            const h = this.camerCom.orthoHeight;
            this.camerCom.orthoHeight = h + 0.01;
            console.log("camerCom.orthoHeight" + this.camerCom.orthoHeight);
        }

        if (event.keyCode == KeyCode.DIGIT_2) {
            const h = this.camerCom.orthoHeight;
            this.camerCom.orthoHeight = h - 0.01;
            console.log("camerCom.orthoHeight" + this.camerCom.orthoHeight);
        }


        if (event.keyCode == (KeyCode.KEY_F)) {
            this.startDrop();
        }
        // console.log("map position" + this.mapNode.worldPosition);
        // console.log("cameraNode worldPosition" + this.cameraNode.worldPosition);

    }




}



/**
 * [1] Class member could be defined like this.
 * [2] Use `property` decorator if your want the member to be serializable.
 * [3] Your initialization goes here.
 * [4] Your update function goes here.
 *
 * Learn more about scripting: https://docs.cocos.com/creator/3.4/manual/en/scripting/
 * Learn more about CCClass: https://docs.cocos.com/creator/3.4/manual/en/scripting/decorator.html
 * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.4/manual/en/scripting/life-cycle-callbacks.html
 */
